package common

import (
	"bufio"
	"crypto/rand"
	"errors"
	"fmt"
	"huijing_mall/shared/kernel/hmErrors"
	"io"
	"log"
	rand1 "math/rand"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"

	"github.com/gin-gonic/gin"
	"github.com/go-rod/rod"
	"github.com/go-rod/rod/lib/launcher"

	"github.com/shopspring/decimal"
	"github.com/yinheli/qqwry"
)

// 错误
func FailOnError(err error, msg string) {
	if err != nil {
		log.Panicf("%s: %s", msg, err)
	}
}

func JoinStr(msg ...string) string {
	// 先计算总长度，再预分配
	total := 0
	for _, v := range msg {
		total += len(v)
	}
	var builder strings.Builder
	builder.Grow(total) // 精准 分配 内存 字节
	for _, v := range msg {
		builder.WriteString(v)
	}
	return builder.String()
}

func StrPinJie(msg ...string) string {
	// 先计算总长度，再预分配
	total := 0
	for _, v := range msg {
		total += len(v)
	}
	var builder strings.Builder
	builder.Grow(total) // 精准 分配 内存 字节
	for _, v := range msg {
		builder.WriteString(v)
	}
	return builder.String()
}

type TypeNil struct {
	Value any
	Str   string
	Int   int
	Flt   float64
	Bt    byte
	Bl    bool
	Err   error // 用 Err 代替 Df，更符合 Go 习惯
}

// AnyType 安全解析 Value 并填充对应字段
func (a *TypeNil) AnyType() {
	if a.Value == nil {
		a.Err = errors.New("value is nil")
		return
	}

	switch v := a.Value.(type) {
	case string:
		a.Str = a.AnyToStr()
	case int:
		a.Int = a.AnyToInt()
	case float64:
		a.Flt = a.AnyToFlt()
	case byte:
		a.Bt = a.AnyToBt()
	case bool:
		a.Bl = a.AnyToBl()
	default:
		a.Err = fmt.Errorf("unsupported type: %T", v)
	}
}

func (a *TypeNil) AnyToStr() string {
	return a.Value.(string)
}

func (a *TypeNil) AnyToInt() int {
	return a.Value.(int)
}

func (a *TypeNil) AnyToFlt() float64 {
	return a.Value.(float64)
}

func (a *TypeNil) AnyToBt() byte {
	return a.Value.(byte)
}

func (a *TypeNil) AnyToBl() bool {
	return a.Value.(bool)
}

var areaMap map[string]string

// 解析SQL文件
func ParseSQLToMap(sqlFileName string) (err error) {
	// 读取 SQL 文件内容
	file, err := os.Open(sqlFileName)
	if err != nil {
		fmt.Println("Error opening file:", err)
		return
	}
	defer file.Close()

	// 创建一个 map 来存储 city_name 和 city_code
	areaMap = make(map[string]string)

	// 改进后的正则表达式
	//insertRegex := regexp.MustCompile(`INSERT INTO \`area\` VALUES\s*\(\s*'([^']*)'\s*,\s*'([^']*)'\s*(?:,\s*[^)]*)?\)`)

	// 逐行读取文件内容
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		// 过滤注释和空行
		if strings.HasPrefix(line, "--") || strings.TrimSpace(line) == "" {
			continue
		}
		if strings.Contains(line, "INSERT") {
			idxArr := strings.Split(line, " ")
			//只获取城市名称和代码
			cityName, SymErr := removeSymbols(idxArr[4])
			if SymErr != nil {
				return
			}
			cityCode, SymErr := removeSymbols(idxArr[5])
			if SymErr != nil {
				return
			}
			areaMap[cityName] = cityCode
		}
	}
	if err = scanner.Err(); err != nil {
		fmt.Println("Error reading file:", err)
		return
	}
	return
}

// 去除符号
func removeSymbols(text string) (res string, err error) {
	if strings.Contains(text, "(") {
		text = strings.ReplaceAll(text, "(", "")
	}
	numberStr := strings.ReplaceAll(text, "'", "")
	numberStr = strings.TrimSuffix(numberStr, ",")
	if numberStr == "" {
		fmt.Println("Empty string")
		return "", errors.New("Empty string")
	}
	return numberStr, nil
}

// string to int
func StrToInt(str string) int {
	intValue, err := strconv.Atoi(str)
	if err != nil {
		intValue = int(StrToFloat(str))
	}
	return intValue
}

// int to string
func IntToStr(str int) string {
	return strconv.Itoa(str)
}

// string to Float
func StrToFloat(str string) float64 {
	str = strings.TrimSpace(str)
	str = TrimQff(str)
	intValue, err := strconv.ParseFloat(str, 64)
	if err != nil {
		intValue = 0
	}
	d := decimal.NewFromFloat(intValue)
	f, _ := d.Round(2).Float64()
	return f
}

const charset1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
const charset2 = "0123456789"

// randomString 使用crypto/rand生成一个随机字符串
func RandomString(length int) string {
	charset := ""
	if length <= 11 {
		charset = charset2
	} else {
		charset = charset1
	}
	bytes := make([]byte, length)
	if _, err := rand.Read(bytes); err != nil {
		return ""
	}

	for i, b := range bytes {
		// 这里需要将b转换为byte类型
		bytes[i] = charset[b%byte(len(charset))]
	}

	return string(bytes)
}

func StartsWithZero(s string) bool {
	return strings.HasPrefix(s, "0")
}

func GetRandomString(length int) (code string) {
	for {
		code = RandomString(length)
		if !StartsWithZero(code) && code != "" {
			break
		}
	}
	return
}

func RandomUUIDStyleNickname() string {
	uuidPart := fmt.Sprintf("%04x", rand1.Intn(0x10000)) // 4位随机16进制
	return StrPinJie("user-", uuidPart)
}

// string 去千分符
func TrimQff(str string) string {
	return strings.Replace(str, ",", "", -1)
}

// 拦截 请求
//func Hijack(p *rod.Page, pattern string) {
//	r := p.HijackRequests()
//	ch := make(chan string)
//	r.MustAdd("*"+pattern+"*", func(ctx *rod.Hijack) {
//		//代理使用再需要
//		//if lr.UseProxy {
//		//	err = ctx.LoadResponse(c, true)
//		//	if err != nil {
//		//		return
//		//	}
//		//} else {
//		ctx.MustLoadResponse()
//		//}
//		ch <- ctx.Response.Body()
//		ctx.Response.Payload()
//	})
//}

// 信息管道 ch 等待时间 t （单位：second）
func getRes(ch chan string, t float64) (string, error) {
	d := time.Duration(t * float64(time.Second))
	select {
	case val := <-ch:
		return val, nil
	case <-time.After(d):
		return "", errors.New("timeout")
	}
}

// 简单的创建浏览器
func NewBrowser() *rod.Browser {
	l := launcher.New().Headless(false)
	//防检测
	l.Flags["disable-blink-features"] = []string{"AutomationControlled"}
	ws, _ := l.Launch()
	return rod.New().ControlURL(ws).MustConnect()
	//return nil
}

// truncateString 根据字符数截取字符串
func TruncateString(s string, maxRunes int) string {
	if utf8.RuneCountInString(s) <= maxRunes {
		return s
	}

	// 截取至最后一个完整的字符
	n := 0
	for i, r := range s {
		if n+utf8.RuneLen(r) > maxRunes {
			return s[:i]
		}
		n++
	}
	return s
}

// 获取访问IP地址
func GetUserIp(g *gin.Context) {
	//c := http.DefaultClient
	//get, err := c.Get("https://myip.ipip.net")
	//if err != nil {
	//	return
	//}
	//defer get.Body.Close()
	//b, _ := io.ReadAll(get.Body)
	OpenWriteFile("userIp", "北京时间："+time.Now().Format(time.DateTime)+" 访问信息："+getIpInfo1(GetClientIP(g.Request))+"\n")
}

func GetClientIP(r *http.Request) string {
	// Cloudflare 优先
	if cfIP := r.Header.Get("CF-Connecting-IP"); cfIP != "" {
		return cfIP
	}

	// 处理 X-Forwarded-For
	if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
		ips := strings.Split(forwarded, ",")
		if ip := strings.TrimSpace(ips[0]); ip != "" {
			return ip
		}
	}

	// 处理 X-Real-IP
	if realIP := r.Header.Get("X-Real-IP"); realIP != "" {
		return realIP
	}

	// 默认从 RemoteAddr 获取
	ip, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		return r.RemoteAddr
	}
	return ip
}

func getIpInfo1(ip string) string {
	// 自动下载纯真数据库（如果本地不存在）
	if _, err := os.Stat("qqwry.dat"); os.IsNotExist(err) {
		fmt.Println("正在下载纯真IP库...")
		resp, err := http.Get("https://qqwry.mirror.noc.one/qqwry.dat")
		if err != nil {
			panic("下载失败: " + err.Error())
		}
		defer resp.Body.Close()

		out, _ := os.Create("qqwry.dat")
		defer out.Close()

		_, err = io.Copy(out, resp.Body)
		if err != nil {
			panic("保存文件失败: " + err.Error())
		}
		fmt.Println("下载完成！")
	}

	// 使用纯真库查询
	q := qqwry.NewQQwry("qqwry.dat")
	q.Find(ip)

	fmt.Printf("IP %s\n", q.Ip)       // 示例输出：山东省青岛市
	fmt.Printf("位置: %s\n", q.Country) // 示例输出：山东省青岛市
	fmt.Printf("运营商: %s\n", q.City)   // 示例输出：联通
	return q.Ip + "-" + q.Country + "-" + q.City
}

// 路径 存在
func PathExists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}

// FileExtensionOptions 配置选项
type FileExtensionOptions struct {
	WithDot      bool // 是否包含点(.)
	ToLower      bool // 是否转为小写
	MultipleDots bool // 是否处理多个点的情况(如.tar.gz)
}

// GetFileExtension 获取文件后缀名
// filename: 文件名
// opts: 配置选项，nil表示使用默认选项
func GetFileExtension(filename string, opts *FileExtensionOptions) string {
	if opts == nil {
		opts = &FileExtensionOptions{
			WithDot:      true,
			ToLower:      false,
			MultipleDots: false,
		}
	}

	ext := filepath.Ext(filename)

	// 处理多个点的情况，如".tar.gz"
	if opts.MultipleDots {
		base := filepath.Base(filename)
		if i := strings.Index(base, "."); i > 0 {
			ext = base[i:]
		}
	}

	// 是否包含点
	if !opts.WithDot && len(ext) > 0 && ext[0] == '.' {
		ext = ext[1:]
	}

	// 是否转为小写
	if opts.ToLower {
		ext = strings.ToLower(ext)
	}

	return ext
}

func MapDelFiled(userMap map[string]interface{}, key []string) {
	for _, v := range key {
		delete(userMap, v)
	}
}

// 根据文件名 打开文件
func CreatOpenFile(fileName string) (*os.File, error) {
	stdoutFile, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		return nil, hmErrors.ErrMsg("创建标准输出文件时出错")
	}
	return stdoutFile, nil
}

// 根据文件名 打开并写入文件
func OpenWriteFile(name, body string) {
	files, _ := os.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	defer func(files *os.File) {
		err := files.Close()
		if err != nil {

		}
	}(files)
	// 写入文件
	_, err := files.WriteString(body)
	if err != nil {
		panic("写入文件时出错:" + err.Error())
	}
}
